/*
泛型
1. 类型未知，可能会有变化，先用一个标识来占位， 以实际传入的类型为准，在使用时才能知道类型；
2. 使用范围，函数， 接口， 类型别名，类
// 用在类上，表示在创建实例的时候传参约束；
// 用在接口上，直接跟在接口名后面
// 泛型用在函数上，写在参数的括号前面,表示实际调用时传入具体类型, 用在函数名后面表示定义参数类型约束
用在接口上表示使用接口时传入类型
3. 泛型约束: 将泛型的可变值限制在某个范围内, <T extends number>
4. 默认泛型， 不指定是就是某默认的类型 <T=string>
5, 约束属性，表示指定的属性必须在某个对象中能找到， 使用 keyof 关键字, keyof 表示取对象中的所有属性
  // type t = keyof any , t 可以是 number|string|symbol 组成的联合类型； 即对象的 key 只能是这三种类型




*/

// 用在函数上，写在参数的括号前面
// 用在接口上，直接跟在接口名后面
// 泛型用在函数上，表示实际调用时传入具体类型, 用在接口上表示使用接口时传入类型
function createArray<T>(times: number, val: T): T[] {
    return new Array(times).fill(val)
}
let aa = createArray(12, 212)

// 交换元组位置
function swap<T, K>(tuple: [T, K]): [K, T] {
    return [tuple[1], tuple[0]]
}
let tt = swap([3, '656'])
console.log(tt);


// 以下在函数和接口中都可以使用泛型
interface MySwap {
    <A, B>(tuple: [A, B]): [B, A]
}
const swap2: MySwap = <A, B>(tuple: [A, B]): [B, A] => {
    return [tuple[1], tuple[0]]
}



// interface IArr<A, B> {
// }
// const swap3 = <A, B>(tuple: { [key: number]: B }): IArr<A, B> => {
//     return [tuple[0], tuple[1]]
// }
// let r1 = swap3([2, 3])

// 等同于以下代码
interface IArr<A, B> {
    [key: number]: B
}
const swap3 = <A, B>(tuple: IArr<A, B>): IArr<A, B> => {
    return [tuple[0], tuple[1]]
}
let r1 = swap3(['2', 3]) // 传给 IArr<A, B>后， B 得到了值， A 什么也没得到，所以 A 是 unknow
let r2 = swap3<string, number>([2, 3])








class Person {
    constructor(public name: string) {
        this.name = name
    }
}
// 描述类的实例，泛型直接跟在接口名后面
interface IClass<T> {
    new(name: string): T, // 描述类的实例
}

// 以下三种都可以作为 clazz 的类型
// { new(name: string): any }
//  new(name: string)=> any 
// IClass

function createInstance<T>(clazz: IClass<T>, name: string) {
    return new clazz(name)
}

let r = createInstance<Person>(Person, '张三') //  此处是入口






//-----------------泛型约束----------------------------
const sum = <T extends string>(a: T, b: T): T => {
    return (a + b) as T // 用 as 强转
}
let sum1 = sum<string>('ere', 'ere')

// 约束参数必须要有 length 属性
type withLength = { length: number }
function getType<T extends withLength>(obj: T) {
    obj.length
}
getType({ length: 323 })
getType([])
getType('43434')
//---------------------------------------------


//-----------------默认泛型--------------------
interface Dstr<T = string> { // 如果不指定就是 string
    name: T
}
type T1 = Dstr // 没有传入实际类型
let str1: T1 = { name: '344' }

type T2 = Dstr<number> // 传入 number 型
let str2: T2 = { name: 4343 }
//---------------------------------------------


//-----------------约束属性----------------------
// 约束泛型中的 K 必须是对象 T 中的某个 key ， 使用 keyof 关键字
function getVal<T extends object, K extends keyof T>(obj: T, key: K) {
    return 'xxx'
}
getVal({ a: 're', b: 'rer' }, 'a')

type t1 = keyof any  // number | string | symbol, 对象的 key 仅限于这三种类型
type t2 = keyof (number | string) //  toString | valueOf ， 共同的 key 
//---------------------------------------------

//----------------用在类上---------------------
class MyArray<T>{
    public arr: T[] = []
    add(v: T) {
        this.arr.push(v)
    }
    getMax(): T {
        let arr = this.arr
        let max = this.arr[0]
        for (let i = 0; i < arr.length; i++) {
            let current = arr[i]
            current > max ? max = current : void 0
        }
        return max
    }
}

let arr1 = new MyArray<number>() // 实例化时约束
arr1.add(323)
arr1.add(1)
arr1.add(1)
arr1.add(1)
arr1.getMax()
//---------------------------------------------






export { }